/**
 *
 * @author 朱雀
 */
Ext.define('SvgEditor.canvas.Operation', {
	addKnuckle: function(canvas) {
		canvas = canvas || this;
		var flow = canvas.selected[0] && canvas.selected[0].type === 'path' ? canvas.selected[0] : null
		if (flow) {
			var path = flow.attrs.path,
					msg = [canvas.locale.canvasPanel.operation.addKnuckle.msg[0], path.length - 2,
						canvas.locale.canvasPanel.operation.addKnuckle.msg[1], path.length - 2].join(""),
					dialog = Ext.Msg.show({
						title: canvas.locale.canvasPanel.operation.addKnuckle.title,
						msg: msg,
						width: 300,
						buttons: Ext.Msg.OKCANCEL,
						prompt: true,
//				multiline: true,
						fn: function(btn, text, me) {
							if (btn === 'ok' && text && text !== '') {
								var index = parseInt(text);
								if (index > path.length - 2) {
									index = path.length - 2;
								}
								index += 1;
								Ext.Array.insert(path, index, [[]]);
								path[index] = ['L', (path[index - 1][1] + path[index + 1][1]) / 2, (path[index - 1][2] + path[index + 1][2]) / 2];
								flow.attr({path: path});
								canvas.viewAnchor(canvas, flow);
							} else {
								return;
							}
						},
						icon: Ext.MessageBox.INFO
					});
		}
	},
	removeKnuckle: function(canvas, flow) {
		canvas = canvas || this;
		var flow = canvas.selected[0] && canvas.selected[0].type === 'path' ? canvas.selected[0] : null,
				path = flow.attrs.path;
		if (flow && path.length > 2) {
			var msg = [canvas.locale.canvasPanel.operation.removeKnuckle.msg[0], path.length - 2,
				canvas.locale.canvasPanel.operation.removeKnuckle.msg[1], path.length - 3].join(""),
					dialog = Ext.Msg.show({
						title: canvas.locale.canvasPanel.operation.removeKnuckle.title,
						msg: msg,
						width: 300,
						buttons: Ext.Msg.OKCANCEL,
						prompt: true,
//				multiline: true,
						fn: function(btn, text, me) {
							if (btn === 'ok' && text && text !== '') {
								var index = parseInt(text);
								if (index > path.length - 3) {
									index = path.length - 3;
								}
								index += 1;
								Ext.Array.remove(path, path[index]);
								if (flow.flowFrom) {
									path[0] = ['M', flow.flowFrom.coreX, flow.flowFrom.coreY];
								}
								if (flow.flowTo) {
									path[path.length - 1] = ['L', flow.flowTo.coreX, flow.flowTo.coreY];
								}
								flow.attr({path: path});
								canvas.connect(flow);
								canvas.viewAnchor(canvas, flow);
							} else {
								return;
							}
						},
						icon: Ext.MessageBox.INFO
					});
		}
	},
	getModelById: function(canvas, id) {
		return canvas.paper.getById(id);
	},
	setModelId: function(model, id) {
		if (model) {
			model.id = model.node.raphaelid = id;
		}
	},
	setModelAttrs: function(model, attrs) {
		if (model) {
			model.attr(attrs);
			if (model.type === 'circle' || model.type === 'ellipse') {
				model.coreX = model.attrs.cx;
				model.coreY = model.attrs.cy;
			} else if (model.type === 'image' || model.type === 'rect') {
				model.coreX = model.attrs.x + model.attrs.width / 2;
				model.coreY = model.attrs.y + model.attrs.height / 2;
			}
		}
	},
	getFlowFrom: function(model) {
		return model.flowFrom;
	},
	getFlowTo: function(model) {
		return model.flowTo;
	},
	createModel: function(canvas, modelConfig) {
		return canvas.mixins[modelConfig.type].init(canvas, modelConfig);
	},
	addModel: function(canvas, modelConfig, x, y, byDD) {
		canvas = canvas || this;
		if (!modelConfig.data) {
			modelConfig.data = {modelType: modelConfig.id};
		} else if (modelConfig.data && !modelConfig.data.modelType) {
			Ext.apply(modelConfig.data, {modelType: modelConfig.id});
		}
		if (x && y) {
			x = x - canvas.origin.offsetX;
			y = y - canvas.origin.offsetY;
		} else {
			x = 100, y = 50;
		}
		var model;
		if (modelConfig.type === 'path') {
			var path = [
				['M', (x - 50), y],
				['L', (x + 50), y]
			], pathConfig = {
				type: 'path',
				data: modelConfig.data,
				attrs: {
					path: path,
					stroke: 'black',
					'stroke-width': 2,
					'arrow-end': 'classic-wide-long'
				}
			};
			if (modelConfig.attrs) {
				Ext.apply(pathConfig.attrs, modelConfig.attrs);
			}
			model = canvas.createModel(canvas, pathConfig);
		} else if (modelConfig.type === 'circle') {
			var circleConfig = {
				type: 'circle',
				data: modelConfig.data,
				attrs: {
					cx: x, cy: y, r: modelConfig.r || 20, fill: 'white'
				}
			};
			if (modelConfig.attrs) {
				Ext.apply(circleConfig.attrs, modelConfig.attrs);
			}
			model = canvas.createModel(canvas, circleConfig);
		} else if (modelConfig.type === 'ellipse') {
			var ellipseConfig = {
				type: 'ellipse',
				data: modelConfig.data,
				attrs: {
					cx: x, cy: y,
					rx: modelConfig.rx || 50, ry: modelConfig.ry || 40,
					fill: 'white'
				}
			};
			if (modelConfig.attrs) {
				Ext.apply(ellipseConfig.attrs, modelConfig.attrs);
			}
			model = canvas.createModel(canvas, ellipseConfig);
		} else if (modelConfig.view) {
			var imageConfig = {
				type: 'image',
				data: modelConfig.data,
				attrs: {
					src: modelConfig.view,
					x: x, y: y, fill: 'white',
					width: modelConfig.width || 100, height: modelConfig.height || 80
				}
			};
			if (modelConfig.attrs) {
				Ext.apply(imageConfig.attrs, modelConfig.attrs);
			}
			model = canvas.createModel(canvas, imageConfig);
		} else {
			var rectConfig = {
				type: 'rect',
				data: modelConfig.data,
				attrs: {
					x: x, y: y, fill: 'white',
					width: modelConfig.width || 100, height: modelConfig.height || 80
				}
			};
			if (modelConfig.attrs) {
				Ext.apply(rectConfig.attrs, modelConfig.attrs);
			}
			model = canvas.createModel(canvas, rectConfig);
		}
		if (x && y && byDD) {
			x = model.attrs.x - (model.coreX - model.attrs.x);
			y = model.attrs.y - (model.coreY - model.attrs.y);
			canvas.setModelAttrs(model, {x: x, y: y});
		}
		if (byDD && canvas.selected.length === 1 && model.type !== 'path') {
			canvas.link(canvas, canvas.selected[0], model);
		}
		canvas.selectModel(canvas, model);
		return model;
	},
	copy: function(canvas) {
		canvas = canvas || this;
		if (canvas.selected.length > 0) {
			canvas.ClipBoard = canvas.selected;
		}
	},
	paste: function(canvas) {
		canvas = canvas || this;
		var newSelected = [], offsetX = 50, offsetY = 50;
		Ext.each(canvas.ClipBoard, function(model) {
			var newModelConfig = {
				type: model.type,
				data: model.data(),
				attrs: Ext.decode(Ext.encode(model.attrs))
			};
			if (model.text) {
				var textConfig = {
					type: 'text',
					attrs: Ext.decode(Ext.encode(model.text.attrs))
				};
				textConfig.attrs.x += offsetX;
				textConfig.attrs.y += offsetY;
				newModelConfig.text = textConfig;
			}
			if (model.type === 'circle' || model.type === 'ellipse') {
				newModelConfig.attrs.cx += offsetX;
				newModelConfig.attrs.cy += offsetY
			} else if (model.type === 'path') {
				var path = newModelConfig.attrs.path;
				Ext.each(path, function(item) {
					item[1] += offsetX;
					item[2] += offsetY;
				});
			} else {
				newModelConfig.attrs.x += offsetX;
				newModelConfig.attrs.y += offsetY;
			}
			var newModel = canvas.createModel(canvas, newModelConfig);
			newSelected.push(newModel);
		});
		canvas.ClipBoard = canvas.selected = newSelected;
		if (newSelected.length == 1) {
			canvas.selectModel(canvas, newSelected[0]);
		} else {
			var selectBox = canvas.selectBox, x = selectBox.attrs.x, y = selectBox.attrs.y;
			x += offsetX;
			y += offsetY;
			canvas.selectBox.attr({x: x, y: y});
		}
	},
	removeModel: function(canvas) {
		canvas = canvas || this;
		if (canvas.selected.length > 0) {
			Ext.each(canvas.selected, function(model) {
				if (model.text) {
					model.text.remove();
				}
				if (model.flowPlate) {
					model.flowPlate.remove();
				}

				if (Array.isArray(model.flowFrom)) {
					Ext.each(model.flowFrom, function(ff) {
						var src = ff.flowFrom;
						Ext.Array.remove(src.flowTo, ff);
						if (ff.text) {
							ff.text.remove();
						}
						ff.flowPlate.remove();
						ff.remove();
					});
				} else if (model.flowFrom) {
					Ext.Array.remove(model.flowFrom.flowTo, model);
				}
				if (Array.isArray(model.flowTo)) {
					Ext.each(model.flowTo, function(ft) {
						var target = ft.flowTo;
						Ext.Array.remove(target.flowFrom, ft);
						if (ft.text) {
							ft.text.remove();
						}
						ft.flowPlate.remove();
						ft.remove();
					});
				} else if (model.flowTo) {
					Ext.Array.remove(model.flowTo.flowFrom, model);
				}
				model.remove();
			});
			canvas.selected = [];
			canvas.selectModel(canvas);
			canvas.selectBox.hide();
			canvas.widget.hide();
		}
	},
	link: function(canvas, src, target) {
		canvas = canvas || this;
		if (src && target) {
			if (src.type === 'path' || target.type === 'path') {
				return;
			} else {
				var path = [
					['M', src.coreX, src.coreY],
					['L', target.coreX, target.coreY]
				], pathConfig = {
					type: 'path',
					attrs: {
						path: path,
						stroke: 'black',
						'stroke-width': 2,
						'arrow-end': 'classic-wide-long'
					}
				},
				flow = canvas.createModel(canvas, pathConfig);
				canvas.connect(flow, src, target);
			}
		}
	},
	connect: function(flow, src, target) {
		if (src) {
			if (src.id === 'startP') {
				if (flow.flowFrom) {
					Ext.Array.remove(flow.flowFrom.flowTo, flow);
				}
				flow.flowFrom = null;
			} else {
				flow.flowFrom = src;
				src.flowTo.push(flow);
			}
		} else {
			src = flow.flowFrom;
		}
		if (target) {
			if (target.id === 'endP') {
				if (flow.flowTo) {
					Ext.Array.remove(flow.flowTo.flowFrom, flow);
				}
				flow.flowTo = null;
			} else {
				flow.flowTo = target;
				target.flowFrom.push(flow);
			}
		} else {
			target = flow.flowTo;
		}
		var pi = Math.PI, path = flow.attrs.path, start = flow.start, end = flow.end, angle, util = flow.canvas.util;

		if (src) {
			var secondStart = [path[1][1], path[1][2]], srcBox = src.getBBox();
			angle = Raphael.angle(src.coreX, src.coreY, secondStart[0], secondStart[1]) - 180;
			if (src.type === 'circle') {
				var r = src.attrs.r + 2, cos = Math.cos(angle / 180 * pi), sin = Math.sin(angle / 180 * pi);
				var a = r * util.minimum(cos), b = r * util.minimum(sin);
				start = [src.coreX + a, src.coreY + b];
			} else {
				if (angle == -135) {
					start[0] = srcBox.x - 2;
					start[1] = srcBox.y - 2;
				} else if (angle == -45) {
					start[0] = srcBox.x + 2;
					start[1] = srcBox.y - 2;
				} else if (angle == 45) {
					start[0] = srcBox.x + 2;
					start[1] = srcBox.y + 2;
				} else if (angle == 135) {
					start[0] = srcBox.x - 2;
					start[1] = srcBox.y + 2;
				} else if (angle > 135 || angle < -135) {
					start[0] = srcBox.x - 2;
					a = src.coreX - start[0];
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					start[1] = src.coreY - b;
				} else if (angle > -135 && angle < -45) {
					angle += 90;
					start[1] = srcBox.y - 2;
					a = src.coreY - start[1];
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					start[0] = src.coreX + b;
				} else if (angle > -45 && angle < 45) {
					start[0] = srcBox.x2 + 2;
					a = start[0] - src.coreX;
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					start[1] = src.coreY + b;
				} else if (angle > 45 && angle < 135) {
					angle -= 90;
					start[1] = srcBox.y2 + 2;
					a = start[1] - src.coreY;
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					start[0] = src.coreX - b;
				}
			}
		}

		if (target) {
			var secondEnd = [path[path.length - 2][1], path[path.length - 2][2]], targetBox = target.getBBox();
			angle = Raphael.angle(target.coreX, target.coreY, secondEnd[0], secondEnd[1]) - 180;
			if (target.type === 'circle') {
				var r = target.attrs.r + 2, cos = Math.cos(angle / 180 * pi), sin = Math.sin(angle / 180 * pi);
				var a = r * util.minimum(cos), b = r * util.minimum(sin);
				end = [target.coreX + a, target.coreY + b];
			} else {
				var a, b;
				if (angle == -135) {
					start[0] = srcBox.x - 2;
					start[1] = srcBox.y - 2;
				} else if (angle == -45) {
					start[0] = srcBox.x + 2;
					start[1] = srcBox.y - 2;
				} else if (angle == 45) {
					start[0] = srcBox.x + 2;
					start[1] = srcBox.y + 2;
				} else if (angle == 135) {
					start[0] = srcBox.x - 2;
					start[1] = srcBox.y + 2;
				} else if (angle > 135 || angle < -135) {
					end[0] = targetBox.x - 2;
					a = target.coreX - end[0];
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					end[1] = target.coreY - b;
				} else if (angle > -135 && angle < -45) {
					angle += 90;
					end[1] = targetBox.y - 2;
					a = target.coreY - end[1];
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					end[0] = target.coreX + b;
				} else if (angle > -45 && angle < 45) {
					end[0] = targetBox.x2 + 2;
					a = end[0] - target.coreX;
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					end[1] = target.coreY + b;
				} else if (angle > 45 && angle < 135) {
					angle -= 90;
					end[1] = targetBox.y2 + 2;
					a = end[1] - target.coreY;
					b = Math.ceil(a * util.minimum(Math.tan(angle / 180 * pi)));
					end[0] = target.coreX - b;
				}
			}
		}
		var flowPlate = flow.flowPlate;
		path[0] = ['M', start[0], start[1]];
		path[path.length - 1] = ['L', end[0], end[1]];
		flow.attr({path: path});
		flowPlate.attr({path: path});
		flowPlate.start = flow.start = start;
		flowPlate.end = flow.end = end;
	},
	setDiagram: function(canvas, diagram) {
		canvas = canvas || this;
		Ext.each(diagram, function(modelConfig) {
			canvas.createModel(canvas, modelConfig);
		});
		Ext.each(diagram, function(modelConfig) {
			var model = canvas.paper.getById(modelConfig.modelId);
			if (Array.isArray(modelConfig.flowFromId)) {
				Ext.each(modelConfig.flowFromId, function(ffi) {
					var flowFrom = canvas.paper.getById(ffi);
					model.flowFrom.push(flowFrom);
				});
			} else {
				model.flowFrom = canvas.paper.getById(modelConfig.flowFromId);
			}

			if (Array.isArray(modelConfig.flowToId)) {
				Ext.each(modelConfig.flowToId, function(fti) {
					var flowTo = canvas.paper.getById(fti);
					model.flowTo.push(flowTo);
				});
			} else {
				model.flowTo = canvas.paper.getById(modelConfig.flowToId);
			}
		});
	},
	getDiagram: function(canvas) {
		canvas = canvas || this;
		var ms = canvas.modelSet;
		if (!ms) {
			ms = canvas.modelSet = canvas.paper.setFinish();
		}
		var diagram = [];
		Ext.each(ms.items, function(model) {
			if (model.type !== 'text' && !model.flow) {
				var modelData = model.data();
				var modelConfig = {
					modelId: model.id, type: model.type,
					attrs: model.attrs,
					data: modelData
				};
				if (modelData.text) {
					modelConfig.text = {
						type: 'text',
						attrs: model.text.attrs
					};
				}
				if (Array.isArray(model.flowFrom)) {
					modelConfig.flowFromId = [];
					Ext.each(model.flowFrom, function(ff) {
						modelConfig.flowFromId.push(ff.id);
					});
				} else if (model.flowFrom) {
					modelConfig.flowFromId = model.flowFrom.id;
				}
				if (Array.isArray(model.flowTo)) {
					modelConfig.flowToId = [];
					Ext.each(model.flowTo, function(ft) {
						modelConfig.flowToId.push(ft.id);
					});
				} else if (model.flowTo) {
					modelConfig.flowToId = model.flowTo.id;
				}
				diagram.push(modelConfig);
			}
		});
		canvas.paper.setStart(ms);
		return diagram;
	}
});